/*
 * Sequence.java
 *
 * Created on 20 marzo 2004, 10.26
 */

package net.ermannofranco.xml.schema;

import net.ermannofranco.xml.SyntaxException;

/**
 * 
 * @author ermanno (ermanno.franco@gmail.com)
 */
public class Sequence extends SchemaTag implements ITagCollection {

	/**
	 * 
	 */
	private static final long serialVersionUID = 2939541453410544593L;
	private boolean allowOccurrences;

	// public static int UNBOUNDED=0;

	/**
	 * Creates a new instance of SimpleContent Protetto
	 * 
	 * @param level
	 *            livello di indentazione
	 * @param container
	 *            tag contenitore
	 */
	protected Sequence(int level, ISchemaTag container, boolean allowOccurrences) {
		super("sequence", level, container);
		this.allowOccurrences = allowOccurrences;
	}

	public Element addElem(Element ref) {
		Element e;
		add(e = new Element(getLevel() + 1, this));
		e.setRef(ref);
		return e;
	}

	public Element addElem(String name) {
		Element e;
		add(e = new Element(getLevel() + 1, this));
		e.setName(name);
		return e;
	}

	public Element addElem(String name, XmlType type) {
		Element e;
		add(e = new Element(getLevel() + 1, this));
		e.setNameAndType(name, type);
		return e;
	}

	public Element addElem(String name, ContentType typeRef) {
		Element e;
		add(e = new Element(getLevel() + 1, this));
		e.setNameAndType(name, typeRef);
		return e;
	}

	public Element addElem(String name, String typeName) {
		Element e;
		add(e = new Element(getLevel() + 1, this));
		e.setNameAndType(name, typeName);
		return e;
	}

	public Sequence addSequence() {
		Sequence s;
		add(s = new Sequence(getLevel() + 1, this, true));
		return s;
	}

	public Choice addChoice() {
		Choice s;
		add(s = new Choice(getLevel() + 1, this));
		return s;
	}

	public Group addGroup() {
		Group s;
		add(s = new Group(getLevel() + 1, this));
		return s;
	}

	public Any addAny() {
		Any s;
		add(s = new Any(getLevel() + 1, this));
		return s;
	}

	public Any addAny(String... namespace) {
		return addAny().setNamespace(namespace);
	}

	public Any addAny(NsConstants namespace, Process processContent) {
		return addAny().setNamespace(namespace.getVal()).processContents(
				processContent);
	}

	public Any addAny(Process processContent) {
		return addAny().processContents(processContent);
	}

	/**
	 * Allow zero or unbounded occurs. Shortcut for
	 * setMinOccurs(0).setUnboundedMaxOccurs().
	 * 
	 * @return this.
	 */
	public Sequence setAllPossibleOccurs() {
		return setMinOccurs(0).setUnboundedMaxOccurs();
	}

	/**
	 * Shortcut for setMinOccurs(0).setMaxOccurs(1). Remember: if maxOccurs is
	 * not specified in element, default is 1 anyway.
	 * 
	 * @return this.
	 */
	public Sequence setZeroOrOneOccurs() {
		return setMinOccurs(0).setMaxOccurs(1);
	}

	/**
	 * Shortcut for setMinOccurs(0).
	 * 
	 * @return this.
	 */
	public Sequence setZeroMinOccurs() {
		return setMinOccurs(0);
	}

	/**
	 * add maxOccurs="unbounded"
	 * 
	 * @return
	 */
	public Sequence setUnboundedMaxOccurs() {
		return setMaxOccurs(Integer.MAX_VALUE);
	}

	public Sequence setMinOccurs(int minOccurs) {
		if (!allowOccurrences) throw new SchemaException("occurs not allowed here");
		if (minOccurs < 0)
			throw new SyntaxException(minOccurs + " non valido in minOccurs: "
					+ getName());
		if (getLevel() == 1)
			throw new SchemaException("minOccurs non valido al primo livello: "
					+ getName());// al 1 livello non e' ammesso
		addAttr("minOccurs", "" + minOccurs);// al 1 livello non e' ammesso
		return this;
	}

	public Sequence setMaxOccurs(int maxOccurs) {
		if (!allowOccurrences) throw new SchemaException("occurs not allowed here");
		if (maxOccurs < 0)
			throw new SyntaxException(maxOccurs + " non valido in maxOccurs: "
					+ getName());
		if (getLevel() == 1)
			throw new SchemaException("maxOccurs non valido al primo livello: "
					+ getName());// al 1 livello non e' ammesso
		if (maxOccurs == Integer.MAX_VALUE) {
			addAttr("maxOccurs", "unbounded");
		} else {
			addAttr("maxOccurs", "" + maxOccurs);
		}
		return this;
	}

	/**
	 * aggiunge un tag Annotation che contiene un tag Documentation
	 * 
	 * @param explanation
	 *            Stringa di documentazione
	 * @return autoriferimento all'oggetto corrente
	 */
	public Sequence addDocumentation(String explanation) {
		addAnnotation().addDocumentation(explanation);
		return this;
	}

	/**
	 * aggiunge un tag Annotation che contiene un tag Documentation
	 * 
	 * @param explanation
	 *            testo della documentazione
	 * @param language
	 *            attributo di xml:lang, seguire le regole di i18n
	 * @return riferimento all'oggetto corrente
	 */
	public Sequence addDocumentation(String explanation, String language) {
		addAnnotation().addDocumentation(explanation, language);
		return this;
	}
}
